home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 September / Macworld (1998-09).dmg / Shareware World / Info / For Developers / MacZoop 1.8.3 / Required Classes / Z Sources / ZMenuBar.cpp < prev    next >
Text File  |  1998-07-09  |  37KB  |  1,446 lines

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZMenuBar.cpp        -- the menubar manager object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "MacZoop.h"
  23. #include    "ProjectSettings.h"
  24. #include    "ZCommander.h"
  25.  
  26.  
  27. #ifndef __BALLOONS__
  28. #include    <balloons.h>
  29. #endif
  30.  
  31.  
  32. extern    ZCommander*        gCurHandler;
  33.  
  34. short        gFontMenuID = 0;
  35.  
  36. /*--------------------------------***  DESTRUCTOR  ***---------------------------------*/
  37.  
  38.  
  39. ZMenuBar::~ZMenuBar()
  40. {
  41.     // menubar must be visible when we quit
  42.     
  43.     if ( mbHiding == MBAR_HIDE )
  44.         ShowHideMenuBar( MBAR_SHOW );
  45.     
  46.     if ( theMenuCmds )
  47.         ForgetObject( theMenuCmds );
  48.         
  49.     if ( theMenus )
  50.         ForgetObject( theMenus );
  51.  
  52.     ReleaseResource((Handle) mBarH );
  53. }    
  54.  
  55.  
  56. /*--------------------------------***  INITMENUBAR  ***--------------------------------*/
  57. /*
  58. initialise the menubar from a MBAR resource
  59. ---------------------------------------------------------------------------------------*/
  60.  
  61. void        ZMenuBar::InitMenuBar()
  62. {
  63.     // create an array for holding our command info
  64.     
  65.     FailNIL( theMenuCmds = new ZArray( sizeof( MenuCmd )));
  66.     FailNIL( theMenus = new ZArray( sizeof( MenuInfRec )));
  67.     
  68.     mbCount = 0;
  69.     miSeed = 1;
  70.     wmMenuID = 0;
  71.     rbPending = FALSE;
  72.     inDispatch = FALSE;
  73.     
  74.     // initially menubar is visible
  75.     
  76.     mBarHeight = GetMBarHeight();
  77.     mbHiding = MBAR_SHOW;
  78.     
  79.     // load the MBAR resource
  80.     
  81.     mBarH = (short**) GetResource( 'MBAR', mBarID );
  82.     FailOSErr( ResError());
  83.     
  84.     HNoPurge((Handle) mBarH );
  85.     
  86.     // read in menus from the MBAR resource
  87.     
  88.     LoadMenus();
  89.     
  90.     HPurge((Handle) mBarH );
  91.     
  92.     // add the standard items (DA's) to the Apple menu
  93.     
  94.     AppendStdItems( kAppleMenuID );    
  95.     
  96.     menuCheckChar = checkMark;
  97.     
  98.     // note how many items are in the help menu so we can correctly
  99.     // identify any items we have added
  100.     
  101.     MenuHandle    helpMenuH;
  102.     
  103.     FailOSErr( HMGetHelpMenuHandle( &helpMenuH )); 
  104.     mHelpOffset = CountMenuItems( helpMenuH );
  105. }    
  106.  
  107.  
  108. /*-------------------------------***  CLICKMENUBAR  ***--------------------------------*/
  109. /*
  110. handle mouse click in the menubar
  111. ---------------------------------------------------------------------------------------*/
  112.  
  113. void        ZMenuBar::ClickMenuBar( const Point mousePt )
  114. {
  115.     long        mSelect;
  116.     
  117.     // initially disable all menu items
  118.     
  119.     DimMenus();
  120.     
  121.     // ask the command chain to reenable the relevant menu items
  122.  
  123.     if ( gCurHandler )
  124.         gCurHandler->UpdateMenus();
  125.  
  126.     // now track and select the menus
  127.     
  128.     mSelect = TrackMenuBar( mousePt );
  129.     
  130.     // dispatch the command
  131.     
  132.     DispatchCommand( mSelect );    
  133. }    
  134.  
  135.  
  136. /*-------------------------------***  TRACKMENUBAR  ***--------------------------------*/
  137. /*
  138. track the menubar, returning the item chosen.
  139. ---------------------------------------------------------------------------------------*/
  140.  
  141. long        ZMenuBar::TrackMenuBar( const Point mouse )    
  142. {
  143.     PauseCursorAnimation( 0 );
  144.  
  145.     return MenuSelect( mouse );
  146. }
  147.  
  148.  
  149. /*------------------------------***  UPDATEMENUBAR  ***--------------------------------*/
  150. /*
  151. redraw the menubar. If the menubar is currently dispatching to the command chain, set
  152. a flag in order to cause us to get redrawn when the command completes. If you don't do
  153. this, the menubar can get itself into a bad visual state.
  154. ---------------------------------------------------------------------------------------*/
  155.  
  156. void        ZMenuBar::UpdateMenuBar()
  157. {
  158.     if ( inDispatch || rbPending )
  159.         rbPending = TRUE;
  160.     else
  161.         DrawMenuBar();
  162. }
  163.  
  164.  
  165. /*------------------------------***  DISPATCHCOMMAND  ***------------------------------*/
  166. /*
  167. look up the command and send it up the chain
  168. ---------------------------------------------------------------------------------------*/
  169.  
  170. void    ZMenuBar::DispatchCommand( const long mSelect )
  171. {
  172.     MenuCmd        mCmd;
  173.     GrafPtr        savePort;
  174.     
  175.     GetPort( &savePort );
  176.     
  177.     // if an item was chosen, look up the command and send it up the chain
  178.     
  179.     mCmd.theCmd = noCommand;
  180.     
  181.     if ( HiWord( mSelect) != 0 && gCurHandler )
  182.     {
  183.         // set the zoom source rect in case the command spawns a window
  184.         #if _ZOOM_RECT_FX
  185.         
  186.         Rect    r;
  187.         
  188.         GetMenuTitleRect( HiWord( mSelect ), &r );
  189.         InsetRect( &r, 20, 4 );
  190.         SetGlobalZoomSource( &r );
  191.  
  192.         #endif
  193.         // if the nominated windows menu, handle the window selection
  194.         
  195.         if ( HiWord( mSelect ) == wmMenuID )
  196.             gWindowManager->SelectWindowFromMenu( LoWord( mSelect ));    
  197.  
  198.         FindMCmd( mSelect, &mCmd );
  199.         
  200.         if ( mCmd.theCmd != parentCmd )
  201.         {
  202.             // if the command was found, pass it up the chain. If not found, we still pass it
  203.             // up the chain, but this time as the direct menuID and itemID chosen. Commander
  204.             // classes can choose which of the two methods (or perhaps both?) to adopt.
  205.             
  206.             inDispatch = TRUE;
  207.             
  208.             if ( mCmd.theCmd != noCommand )
  209.                 gCurHandler->HandleCommand( mCmd.theCmd );
  210.             else
  211.                 gCurHandler->HandleCommand( HiWord( mSelect ), LoWord( mSelect ));    
  212.                 
  213.             inDispatch = FALSE;        
  214.         }
  215.  
  216.         SetTitleHilite( 0, FALSE );
  217.         
  218.         if ( rbPending )
  219.         {
  220.             rbPending = FALSE;
  221.             UpdateMenuBar();
  222.         }
  223.         
  224.         SetPort( savePort );
  225.     }
  226. }    
  227.  
  228.  
  229. /*---------------------------------***  ENABLECMD  ***---------------------------------*/
  230. /*
  231. enable the menu item associated with the command
  232. ---------------------------------------------------------------------------------------*/
  233.  
  234. void        ZMenuBar::EnableCommand( const long cmd )
  235. {
  236.     short    m = 0, i = 0;
  237.     
  238.     FindCommand( cmd, &m, &i );
  239.     
  240.     if ( m && i )
  241.         EnableCommand( m, i );
  242. }    
  243.  
  244. /*---------------------------------***  ENABLECMD  ***---------------------------------*/
  245.  
  246. void        ZMenuBar::EnableCommand( const short menuID, const short itemID )
  247. {
  248.     MenuHandle    mH = FindMenuID( menuID );
  249.     
  250.     if ( mH )
  251.     {
  252.         EnableItem( mH, itemID );
  253.         
  254.         if ( itemID == 0 )
  255.             UpdateMenuBar();
  256.     }
  257. }    
  258.  
  259. /*---------------------------------***  DISABLECMD  ***--------------------------------*/
  260. /*
  261. disable the menu item associated with the command
  262. ---------------------------------------------------------------------------------------*/
  263.  
  264. void        ZMenuBar::DisableCommand( const long cmd )
  265. {
  266.     short    m = 0, i = 0;
  267.     
  268.     FindCommand( cmd, &m, &i );
  269.     
  270.     if ( m && i )
  271.         DisableCommand( m, i );
  272. }    
  273.  
  274. /*---------------------------------***  DISABLECMD  ***--------------------------------*/
  275.  
  276. void        ZMenuBar::DisableCommand( const short menuID, const short itemID )
  277. {
  278.     MenuHandle    mH = FindMenuID( menuID );
  279.     
  280.     if ( mH )
  281.     {
  282.         DisableItem( mH, itemID );
  283.         
  284.         if ( itemID == 0 )
  285.             UpdateMenuBar();
  286.     }
  287. }
  288.  
  289.  
  290. /*--------------------------------***  CHECKCOMMAND  ***-------------------------------*/
  291. /*
  292. check the menu command on or off.
  293. ---------------------------------------------------------------------------------------*/
  294.  
  295. void        ZMenuBar::CheckCommand( const long cmd, const Boolean checkOnOff )
  296. {
  297.     short    m = 0, i = 0;
  298.     
  299.     FindCommand( cmd, &m, &i );
  300.     
  301.     if ( m && i )
  302.         CheckCommand( m, i, checkOnOff );
  303. }
  304.  
  305.  
  306. /*--------------------------------***  CHECKCOMMAND  ***-------------------------------*/
  307.  
  308. void        ZMenuBar::CheckCommand( const short menuID, const short itemID, const Boolean checkOnOff )
  309. {
  310.     MenuHandle    mH = FindMenuID( menuID );
  311.     
  312.     if ( mH )
  313.         SetItemMark( mH, itemID, checkOnOff? menuCheckChar : noMark );
  314. }
  315.  
  316.  
  317. /*--------------------------------***  CHECKCOMMAND  ***-------------------------------*/
  318.  
  319. void        ZMenuBar::CheckCommand( const short menuID, Str255 itemString, const Boolean checkOnOff )
  320. {
  321.     // check the item with the text matching that passed (not case sensitive)
  322.     
  323.     MenuHandle    mH = FindMenuID( menuID );
  324.     Str255        iMatch;
  325.     
  326.     if ( mH )
  327.     {
  328.         short    m = CountMenuItems( mH );
  329.     
  330.         do
  331.         {
  332.             GetMenuItemText( mH, m, iMatch );
  333.             
  334.             if ( EqualString( itemString, iMatch, FALSE, TRUE ))
  335.             {
  336.                 SetItemMark( mH, m, checkOnOff? menuCheckChar : noMark );
  337.                 break;
  338.             }
  339.         }
  340.         while( --m );
  341.     }
  342. }
  343.  
  344.  
  345. /*----------------------------***  CHECKCOMMANDWITHCHAR  ***---------------------------*/
  346.  
  347. void        ZMenuBar::CheckCommandWithChar( const long cmd, const char checkChar )
  348. {
  349.     short    m = 0, i = 0;
  350.     
  351.     FindCommand( cmd, &m, &i );
  352.     
  353.     if ( m && i )
  354.     {
  355.         MenuHandle    mH = FindMenuID( m );
  356.         
  357.         if ( mH )
  358.             SetItemMark( mH, i, checkChar );
  359.     }
  360. }
  361.  
  362.  
  363. /*----------------------------***  CHECKCOMMANDWITHCHAR  ***---------------------------*/
  364.  
  365. void        ZMenuBar::CheckCommandWithChar( const short menuID, Str255 itemString, const char checkChar )
  366. {
  367.     MenuHandle    mH = FindMenuID( menuID );
  368.     Str255        iMatch;
  369.     
  370.     if ( mH )
  371.     {
  372.         short    m = CountMenuItems( mH );
  373.     
  374.         do
  375.         {
  376.             GetMenuItemText( mH, m, iMatch );
  377.             
  378.             if ( EqualString( itemString, iMatch, FALSE, TRUE ))
  379.             {
  380.                 SetItemMark( mH, m, checkChar );
  381.                 break;
  382.             }
  383.         }
  384.         while( --m );
  385.     }
  386. }
  387.  
  388.  
  389. /*-------------------------------***  SETCOMMANDTEXT  ***------------------------------*/
  390. /*
  391. set the text of a menu item to the desired string. Can be accessed by command or item.
  392. ---------------------------------------------------------------------------------------*/
  393.  
  394. void        ZMenuBar::SetCommandText( const long cmd, Str255 aText )
  395. {
  396.     short    m = 0, i = 0;
  397.     
  398.     FindCommand( cmd, &m, &i );
  399.     
  400.     if ( m && i )
  401.         SetCommandText( m, i, aText );
  402. }
  403.  
  404.  
  405. /*-------------------------------***  SETCOMMANDTEXT  ***------------------------------*/
  406.  
  407. void        ZMenuBar::SetCommandText( const short menuID, const short itemID, Str255 aText )
  408. {
  409.     MenuHandle    mH;
  410.     
  411.     mH = FindMenuID( menuID );
  412.     
  413.     if ( mH )
  414.         SetMenuItemText( mH, itemID, aText );
  415. }
  416.  
  417.  
  418. /*-------------------------------***  SETCOMMANDTEXT  ***------------------------------*/
  419.  
  420. void        ZMenuBar::SetCommandText( const long cmd, const short strListID, const short strIndex )
  421. {
  422.     Str255    aText;
  423.     
  424.     GetIndString( aText, strListID, strIndex );
  425.     if ( aText[0] > 0 )
  426.         SetCommandText( cmd, aText );
  427. }
  428.  
  429.  
  430. /*-------------------------------***  SETCOMMANDTEXT  ***------------------------------*/
  431.  
  432. void        ZMenuBar::SetCommandText( const short menuID, const short itemID, const short strListID, const short strIndex )
  433. {
  434.     Str255    aText;
  435.     
  436.     GetIndString( aText, strListID, strIndex );
  437.     if ( aText[0] > 0 )
  438.         SetCommandText( menuID, itemID, aText );
  439. }
  440.  
  441. /*----------------------------***  SETCOMMANDTEXTSTYLE  ***---------------------------*/
  442.  
  443. void        ZMenuBar::SetCommandTextStyle( const long cmd, Style aStyle )
  444. {
  445.     short        m = 0, i = 0;
  446.     MenuHandle    mh;
  447.     
  448.     FindCommand( cmd, &m, &i );
  449.     
  450.     if ( m && i )
  451.     {
  452.         mh = FindMenuID( m );
  453.         
  454.         if ( mh )
  455.             SetItemStyle( mh, i, aStyle );
  456.     }
  457. }
  458.  
  459.  
  460. /*-------------------------------***  SHOWHIDEMENUBAR  ***-----------------------------*/
  461. /*
  462. Show or hide the menubar. This can be used in two ways. You can set the menubar hidden
  463. completely by passing MBAR_HIDE, and reshow it with MBAR_SHOW. OR you can pass in
  464. MBAR_HIDE_MOUSEAWARE and a global mouse location to show or hide the bar dynamically as
  465. the user moves the mouse. ZEventHandler will provide this functionality if you define
  466. _AUTO_MBAR_HIDING.
  467. ---------------------------------------------------------------------------------------*/
  468.  
  469. void        ZMenuBar::ShowHideMenuBar( MBarHiding    mHiding, Point gMouseLoc )
  470. {
  471.     Boolean        showIt;
  472.     Rect        msRect;
  473.     GDHandle    theDevice;
  474.     RgnHandle    temp;
  475.     
  476.     if ( mHiding != mbHiding )
  477.     {
  478.         // state has changed, or we want to determine it from mouse position
  479.     
  480.         theDevice = GetMainDevice();
  481.         msRect = (*theDevice)->gdRect;
  482.         msRect.bottom = msRect.top + mBarHeight;
  483.             
  484.         if ( mHiding == MBAR_HIDE_MOUSEAWARE )
  485.         {
  486.             showIt = PtInRect( gMouseLoc, &msRect );
  487.             
  488.             // if menubar already in indicated state, do nothing
  489.             
  490.             if (( showIt  && ( mbHiding == MBAR_SHOW )) ||
  491.                 ( !showIt && ( mbHiding == MBAR_HIDE )))
  492.                 return;
  493.         }
  494.         else
  495.             showIt = ( mHiding == MBAR_SHOW );
  496.             
  497.         FailNIL( temp = NewRgn());
  498.         RectRgn( temp, &msRect );
  499.  
  500.         if ( showIt )
  501.         {
  502.             LMSetMBarHeight( mBarHeight );
  503.             DiffRgn(LMGetGrayRgn(), temp, LMGetGrayRgn());
  504.             UpdateMenuBar();
  505.             
  506.             mbHiding = MBAR_SHOW;
  507.         }
  508.         else
  509.         {
  510.             LMSetMBarHeight( 0 );
  511.             UnionRgn(LMGetGrayRgn(), temp, LMGetGrayRgn());
  512.             
  513.             
  514.             mbHiding = MBAR_HIDE;
  515.         }
  516.         // calculate and refresh vis regions of windows
  517.         
  518.         PaintBehind( FrontWindow(), temp );
  519.         CalcVisBehind( FrontWindow(),  temp );
  520.         DisposeRgn( temp );
  521.     }
  522. }
  523.  
  524. /*-------------------------------***  SHOWHIDEMENUBAR  ***-----------------------------*/
  525.  
  526.  
  527. void    ZMenuBar::ShowHideMenuBar( MBarHiding mHiding )
  528. {
  529.     Point unused = { 0, 0 };
  530.     
  531.     ShowHideMenuBar( mHiding, unused );
  532. }
  533.  
  534.  
  535. /*-----------------------------***  NOMINATEWINDOWSMENU  ***---------------------------*/
  536. /*
  537. This method can be used to set up an automatic "Windows" menu. To do this, call this
  538. method once your bar is built. This will nominate the menu with the ID passed as the
  539. Windows menu. Any items in the menu already will be retained and work as normal. As
  540. windows are added and deleted in the window manager, this will maintain the menu for you.
  541. ---------------------------------------------------------------------------------------*/
  542.  
  543. void        ZMenuBar::NominateWindowsMenu( const short menuID )    
  544. {
  545.     if ( wmMenuID == 0 )
  546.     {
  547.         MenuHandle    mH = FindMenuID( menuID );
  548.         
  549.         if ( mH )
  550.         {
  551.             wmMenuID = menuID;
  552.             
  553.             SetMenuDimming( menuID, disableCmdsOnly );
  554.             
  555.             // we need to work hand-in-hand with the window manager to
  556.             // keep track of the windows. The Window Manager is best placed to
  557.             // do all this, so we simply hand off the menu to it.
  558.             
  559.             gWindowManager->SetWindowsMenu( mH );
  560.         }
  561.     }
  562. }
  563.  
  564.  
  565. /*-------------------------------***  INSERTHELPITEM  ***------------------------------*/
  566. /*
  567. append the text to the help menu, and return the item number of the resulting item. To
  568. process this item, override HandleCommand and look for kHMHelpMenuID and the item returned
  569. from this method.
  570. ---------------------------------------------------------------------------------------*/
  571.  
  572. short        ZMenuBar::AppendHelpItem( Str255 itemText )        
  573. {
  574.     short        i;
  575.     MenuHandle    helpMenuH;
  576.     
  577.     FailOSErr( HMGetHelpMenuHandle( &helpMenuH ));
  578.     
  579.     i = mHelpOffset + 1;
  580.     AppendMenu( helpMenuH, itemText );    
  581.     
  582.     return i;
  583. }
  584.  
  585.  
  586. /*------------------------------***  APPENDMENUTOBAR  ***------------------------------*/
  587. /*
  588. This can be called to add menus "on the fly" into the bar. This reads a menu from a
  589. MENU or CMNU resource, parses its comands and inserts the menu. Menus can only be added
  590. to the end of the bar. You need to call UpdateMenuBar after this or a series of these.
  591. ---------------------------------------------------------------------------------------*/
  592.  
  593. void        ZMenuBar::AppendMenuToBar( const short menuID  )
  594. {
  595.     Handle    temp;
  596.     
  597.     temp = GetResource( 'CMNU', menuID );
  598.     
  599.     if ( temp )
  600.     {
  601.         LoadCMNUMenu( menuID );
  602.         ReleaseResource( temp );
  603.     }
  604.     else
  605.         LoadMenu( menuID );
  606.     
  607.     mbCount++;    
  608. }
  609.  
  610. /*-----------------------------***  REMOVEMENUFROMBAR  ***-----------------------------*/
  611. /*
  612. This can be called to remove a menu added with the above routine. You need to call
  613. UpdateMenuBar after this or a series of these.
  614. ---------------------------------------------------------------------------------------*/
  615.  
  616. void        ZMenuBar::RemoveMenuFromBar( const short menuID )
  617. {
  618.     MenuHandle    mH;
  619.     
  620.     FailNILParam( mH = GetMenuHandle( menuID ));    
  621.     
  622.     // remove the command entries for this menu and any submenus it is the parent of.
  623.     
  624.     UnloadMenu( mH );
  625.     mbCount--;
  626. }
  627.  
  628.  
  629. /*------------------------------***  UPDATESTYLEMENU  ***------------------------------*/
  630. /*
  631. sets checkmarks agains standard syle command according to style info passed
  632. ---------------------------------------------------------------------------------------*/
  633.  
  634. void        ZMenuBar::UpdateStyleMenu( TEStyleRunInfo* runInfo )
  635. {
  636.     EnableCommand( kCmdPlainText );
  637.     EnableCommand( kCmdBoldText );
  638.     EnableCommand( kCmdItalicText );
  639.     EnableCommand( kCmdUnderlineText );
  640.     EnableCommand( kCmdOutlineText );
  641.     EnableCommand( kCmdShadowText );
  642.     EnableCommand( kCmdCondensedText );
  643.     EnableCommand( kCmdExtendedText );
  644.     
  645.     Style    curStyle = runInfo->runStyles;
  646.     Style    cs = runInfo->contStyles;
  647.     Boolean continuousRun = ( cs == 0xFF );
  648.  
  649.     if (( curStyle & 0x7F ) == 0 )
  650.         CheckCommand( kCmdPlainText, TRUE );
  651.     else
  652.     {
  653.         if ( curStyle & kPlainStyle )
  654.             CheckCommandWithChar( kCmdPlainText, '-' );
  655.         
  656.         if ( curStyle & bold )
  657.             CheckCommandWithChar( kCmdBoldText, ( cs & bold ) == bold? checkMark : '-' );
  658.  
  659.         if ( curStyle & italic )
  660.             CheckCommandWithChar( kCmdItalicText, ( cs & italic ) == italic? checkMark : '-' );
  661.         
  662.         if ( curStyle & underline )
  663.             CheckCommandWithChar( kCmdUnderlineText, ( cs & underline ) == underline? checkMark : '-' );
  664.         
  665.         if ( curStyle & outline )
  666.             CheckCommandWithChar( kCmdOutlineText, ( cs & outline ) == outline? checkMark : '-' );
  667.         
  668.         if ( curStyle & shadow )
  669.             CheckCommandWithChar( kCmdShadowText, ( cs & shadow ) == shadow? checkMark : '-' );
  670.         
  671.         if ( curStyle & condense )
  672.             CheckCommandWithChar( kCmdCondensedText, ( cs & condense ) == condense? checkMark : '-' );
  673.         
  674.         if ( curStyle & extend )
  675.             CheckCommandWithChar( kCmdExtendedText, ( cs & extend ) == extend? checkMark : '-' );
  676.     }
  677. }
  678.  
  679.  
  680. /*----------------------------***  UPDATEFONTSIZEMENU  ***-----------------------------*/
  681. /*
  682. sets checkmark against current font size, plus sets outline style for real font sizes
  683. in the current font. This iterates through the possible commands so it will work no
  684. matter where you have decided to place your size commands. Neat.
  685. ---------------------------------------------------------------------------------------*/
  686.  
  687. void        ZMenuBar::UpdateFontSizeMenu( TEStyleRunInfo* runInfo )
  688. {
  689.     Boolean    contFont, contSize;
  690.     
  691.     contFont = runInfo->fr & kFontIsContinuous;
  692.     contSize = runInfo->fr & kSizeIsContinuous;
  693.     
  694.     long    fCmd;
  695.     short     i;
  696.     Str255    fontName;
  697.     
  698.     for ( fCmd = kCmdStdFontSize7; fCmd <= kCmdStdFontSize72; fCmd++ )
  699.     {
  700.         EnableCommand( fCmd );
  701.         
  702.         if ( contFont && RealFont( runInfo->fonts[0], fCmd - kStdFontSizeBase ))
  703.             SetCommandTextStyle( fCmd, outline );
  704.         else
  705.             SetCommandTextStyle( fCmd, 0 );
  706.     }
  707.  
  708.     if ( contSize )
  709.         CheckCommand( kStdFontSizeBase + runInfo->sizes[0], TRUE );
  710.     else
  711.     {
  712.         // non-continuous sizes, so mark all the listed sizes
  713.         
  714.         for ( i = 0; i < runInfo->numSizes; i++ )
  715.             CheckCommandWithChar( runInfo->sizes[i] + kStdFontSizeBase, '-' );    
  716.     }
  717.     
  718.     if ( gFontMenuID )
  719.     {
  720.         if ( contFont )
  721.         {
  722.             GetFontName( runInfo->fonts[0], fontName );
  723.             CheckCommand( gFontMenuID, fontName, TRUE );
  724.         }
  725.         else
  726.         {
  727.             // non-continous fonts, so mark all the listed fonts
  728.             
  729.             for ( i = 0; i < runInfo->numFonts; i++ )
  730.             {
  731.                 GetFontName( runInfo->fonts[i], fontName );
  732.                 CheckCommandWithChar( gFontMenuID, fontName, '-' );
  733.             }
  734.         }    
  735.     }
  736. }
  737.  
  738.  
  739. /*---------------------------------***  LOADMENUS  ***---------------------------------*/
  740. /*
  741. for each menu in the MBAR, call LoadMenu. This will deal with hierarchical menus, etc.
  742. This method assumes mBarH is valid, and won't be purged.
  743. ---------------------------------------------------------------------------------------*/
  744.  
  745. void        ZMenuBar::LoadMenus( const Boolean autoInstall )
  746. {
  747.     short        i, menuID;
  748.     Handle        temp;
  749.     
  750.     // how many menus in MBAR resource? This is first item in resource.
  751.     
  752.     mbCount = (*mBarH)[0];
  753.     
  754.     // iterate through, looking for MENU or CMNU resources
  755.     
  756.     for ( i = 1; i <= mbCount; i++ )
  757.     {
  758.         menuID = (*mBarH)[i];
  759.         
  760.         // if CMNU resource is available, use that. Otherwise, use MENU resource,
  761.         // possibly parsing it for command numbers
  762.         
  763.         temp = GetResource( 'CMNU', menuID );
  764.         
  765.         if ( temp )
  766.         {
  767.             LoadCMNUMenu( menuID, FALSE, autoInstall );
  768.             ReleaseResource( temp );
  769.         }
  770.         else
  771.             LoadMenu( menuID, FALSE, autoInstall );
  772.  
  773.     }
  774. }    
  775.  
  776. /*----------------------------------***  DIMMENUS  ***---------------------------------*/
  777. /*
  778. dim all of the menu items, according to their flags.
  779. ---------------------------------------------------------------------------------------*/
  780.  
  781. void        ZMenuBar::DimMenus()
  782. {
  783.     // This originally operated by walking the low-memory global menuList, but that does
  784.     // not work when 3rd party extensions install extra menus. Thus we now use our private
  785.     // list of menus to do this operation so we only affect our own menus.
  786.     
  787.     short        i;
  788.     MenuInfRec    mRec;
  789.     
  790.     for ( i = 1; i <= theMenus->CountItems(); i++ )
  791.     {
  792.         // find this menu in our list, and dim it according to the
  793.         // flags there. (Thanks to Jean-Yves Pochez for the improvements to this method)
  794.         
  795.         mRec.macMenu = NULL;
  796.         theMenus->GetArrayItem( &mRec, i );
  797.     
  798.         if ( mRec.macMenu )
  799.         {
  800.             // menu is in our list, so dim it. Note that all menus, including all of
  801.             // the attached hierarchical menus are dimmed by iterating this list. Thus
  802.             // PredimMenu does not need to be recursive, and isn't.
  803.             
  804.             PredimMenu( mRec.macMenu );
  805.         }
  806.     }
  807.  
  808.     // if auto Windows menu in use, set that up as well
  809.     
  810.     if ( wmMenuID > 0 )
  811.         gWindowManager->BuildWindowsMenu();    
  812. }
  813.  
  814.  
  815. /*-------------------------------***  SETMENUDIMMING  ***------------------------------*/
  816. /*
  817. set the dimming options for a particular menu. By default, all menus are dimmed auto-
  818. matically, but if you don't want them dimmed, or partially dimmed, call this with the
  819. required options.
  820. ---------------------------------------------------------------------------------------*/
  821.  
  822. void        ZMenuBar::SetMenuDimming( const short menuID, const DimmingOptions dimOpts )
  823. {
  824.     MenuInfRec    mr;
  825.     Boolean        bUpdate;
  826.     
  827.     mr.macMenu = NULL;
  828.     
  829.     FindMenuInfo( menuID, &mr );
  830.     
  831.     if ( mr.macMenu )
  832.     {
  833.         // if this call will change the state of the dimTitle flag, we need to cause an
  834.         // update to the menubar so that the user sees the change
  835.         
  836.         bUpdate = (( mr.mDimming ^ dimOpts ) & dimTitle ) != 0;
  837.         
  838.         mr.mDimming = dimOpts;
  839.         theMenus->SetArrayItem( &mr, mr.mIndex );
  840.         
  841.         // update the bar if necessary
  842.         
  843.         if ( bUpdate )
  844.         {
  845.             // enable or disable title item
  846.             
  847.             if ( dimOpts & dimTitle )
  848.                 (*mr.macMenu)->enableFlags &= 0xFFFFFFFE;
  849.             else
  850.                 (*mr.macMenu)->enableFlags |= 1;
  851.             
  852.             UpdateMenuBar();
  853.         }
  854.     }
  855. }    
  856.  
  857.  
  858. /*----------------------------------***  LOADMENU  ***---------------------------------*/
  859. /*
  860. can be called recursively- try to load the menu with the ID and any submenus it refers
  861. to. If MENU resources are not found, try CMNU resources.
  862. ---------------------------------------------------------------------------------------*/
  863.  
  864. void        ZMenuBar::LoadMenu( const short menuID, Boolean isHMenu, Boolean autoInstall )
  865. {
  866.     short        i, mCount, cmdChar, subID;
  867.     MenuHandle    mH;
  868.     MenuCmd        mCmd;
  869.     MenuInfRec    mRec;
  870.     Str255        iText;
  871.     
  872.     FailNILRes( mH = GetMenu( menuID ));
  873.     
  874.     // set up info record for this menu
  875.     
  876.     mRec.menuID = menuID;
  877.     mRec.mIndex = miSeed++;
  878.     mRec.macMenu = mH;
  879.     mRec.mDimming = dimCommands;
  880.     mRec.mIsResource = TRUE;
  881.     
  882.     theMenus->AppendItem( &mRec );
  883.     
  884.     // look through the menu for submenus, and recursively add them
  885.     
  886.     mCount = CountMenuItems( mH );
  887.     
  888.     for( i = 1; i <= mCount; i++ )
  889.     {
  890.         GetMenuItemText( mH, i, iText );
  891.         
  892.         if ( iText[1] != '-' )
  893.         {
  894.             // make a command entry for the item
  895.             
  896.             mCmd.menuID = menuID;
  897.             mCmd.itemID = i;
  898.             mCmd.macMenu = mH;
  899.             
  900.             ParseMenuItem( iText, &mCmd.theCmd );
  901.             
  902.             // menus created using GetMenu are resources, CMNU are not. This is flagged so
  903.             // we can dispose of it correctly.
  904.             
  905.             mCmd.cmdFlags = autoUnCheck | ( isHMenu? 0 : isPrimaryMenu ) | menuIsResource;
  906.             mCmd.subMenuID = 0;
  907.             
  908.             SetMenuItemText( mH, i, iText );
  909.             GetItemCmd( mH, i, &cmdChar );
  910.             
  911.             if ( cmdChar == hMenuCmd )
  912.             {
  913.                 // has a submenu, so load it:
  914.                 
  915.                 GetItemMark( mH, i, &subID );
  916.                 
  917.                 // need to determine if submenu is a MENU or CMNU resource:
  918.                 
  919.                 Handle    cmnuH;
  920.                 
  921.                 cmnuH = GetResource( 'CMNU', subID );
  922.                 
  923.                 if ( cmnuH )
  924.                 {
  925.                     LoadCMNUMenu( subID, TRUE, autoInstall );
  926.                     ReleaseResource( cmnuH );
  927.                 }
  928.                 else
  929.                     LoadMenu( subID, TRUE, autoInstall );
  930.                     
  931.                 mCmd.subMenuID = subID;
  932.                 mCmd.theCmd = parentCmd;
  933.             }
  934.             
  935.             theMenuCmds->AppendItem( &mCmd );
  936.         }
  937.     }
  938.     
  939.     // add the menu to the system list
  940.     
  941.     if ( autoInstall )
  942.         InsertMenu( mH, isHMenu? hierMenu : 0 );
  943. }    
  944.  
  945. /*--------------------------------***  LOADCMNUMENU  ***-------------------------------*/
  946. /*
  947. ditto for CMNU resources- this can parse that format of resource.
  948. ---------------------------------------------------------------------------------------*/
  949.  
  950. void        ZMenuBar::LoadCMNUMenu( const short menuID, Boolean isHMenu, Boolean autoInstall )
  951. {
  952.     CMNUResHdl    cH;
  953.     MenuCmd        mCmd;
  954.     MenuInfRec    mRec;
  955.     MenuHandle    mH;
  956.     Ptr            cmP, cmItemText;
  957.     short        itemID;
  958.     
  959.     cH = ( CMNUResHdl ) GetResource( 'CMNU', menuID );
  960.     
  961.     if ( cH )
  962.     {
  963.         // we need to do two things with this menu- a) make a normal menu handle that
  964.         // can be inserted into the menu manager list, and b) a set of menuCmd records
  965.         // so that we can look up the command when an item is chosen.
  966.     
  967.         FailNIL( mH = NewMenu( menuID, (ConstStr255Param) &(*cH)->mTitle ));
  968.         
  969.         // set up info record for this menu
  970.         
  971.         mRec.menuID = menuID;
  972.         mRec.mIndex = miSeed++;
  973.         mRec.macMenu = mH;
  974.         mRec.mDimming = dimCommands;
  975.         mRec.mIsResource = FALSE;
  976.         
  977.         theMenus->AppendItem( &mRec );
  978.         
  979.         HLock((Handle) cH );
  980.         
  981.         // we need to iterate through the items in the CMNU and build our two structures
  982.         // as needed. To do this efficiently, we lock the handle and keep a running pointer.
  983.         
  984.         cmItemText = cmP = &(*cH)->mTitle + (*cH)->mTitle + 1;
  985.         itemID = 0;
  986.         
  987.         // we're now at the start of the first item's text. We now scan through each item
  988.         // building both the real menu and the command structure
  989.         
  990.         while( *cmItemText != 0 )
  991.         {
  992.             itemID++;
  993.             
  994.             cmP += *cmItemText + 1;        // point to top of "interesting" info
  995.             
  996.             // add text of item, making sure meta-characters are ignored. Note that
  997.             // a dividing line still works correctly
  998.             
  999.             AppendMenu( mH, "\px" );
  1000.             SetMenuItemText( mH, itemID, (ConstStr255Param) cmItemText );
  1001.             
  1002.             // add command entry if not a dividing line
  1003.             
  1004.             if ( cmItemText[1] != '-' )
  1005.             {
  1006.                 // make menu item match info
  1007.                 
  1008.                 SetItemIcon    ( mH, itemID, ((CMNUEntryPtr) cmP)->iconID );
  1009.                 SetItemCmd    ( mH, itemID, ((CMNUEntryPtr) cmP)->keyEqu );
  1010.                 SetItemMark    ( mH, itemID, ((CMNUEntryPtr) cmP)->markChar );
  1011.                 SetItemStyle( mH, itemID, ((CMNUEntryPtr) cmP)->iStyle );
  1012.                 
  1013.                 mCmd.menuID = menuID;
  1014.                 mCmd.itemID = itemID;
  1015.                 mCmd.subMenuID = 0;
  1016.                 mCmd.macMenu = mH;
  1017.                 mCmd.cmdFlags = autoUnCheck | ( isHMenu? 0 : isPrimaryMenu );
  1018.                 mCmd.theCmd = noCommand;
  1019.                 
  1020.                 // if there's a sub-menu, we'll need to find and load it too. This involves
  1021.                 // a recursion to this function or to LoadMenu.
  1022.                 
  1023.                 if (((CMNUEntryPtr) cmP)->keyEqu == hMenuCmd )
  1024.                 {
  1025.                     mCmd.subMenuID = ((CMNUEntryPtr) cmP)->markChar;
  1026.                 
  1027.                     // is this a CMNU or a MENU resource?
  1028.                     
  1029.                     Handle    cmnuH = GetResource( 'CMNU', mCmd.subMenuID );
  1030.                     
  1031.                     if ( cmnuH )
  1032.                     {
  1033.                         LoadCMNUMenu( mCmd.subMenuID, TRUE, autoInstall );
  1034.                         ReleaseResource( cmnuH );
  1035.                     }
  1036.                     else
  1037.                         LoadMenu( mCmd.subMenuID, TRUE, autoInstall );
  1038.                         
  1039.                     mCmd.theCmd = parentCmd;
  1040.                 }
  1041.                 else
  1042.                 {
  1043.                     // set up the command entry for the item. The command number
  1044.                     // may follow a pad byte if it would otherwise be at an odd address, so the
  1045.                     // data lies 4 or 5 bytes away from where cmP is now:
  1046.                 
  1047.                     if ((unsigned long) cmP & 1 )
  1048.                         mCmd.theCmd = *(long*)( cmP + sizeof( CMNUEntry ) + 1 );
  1049.                     else
  1050.                         mCmd.theCmd = *(long*)( cmP + sizeof( CMNUEntry ));
  1051.                 }
  1052.                 // add the item to our command array
  1053.                 
  1054.                 theMenuCmds->AppendItem( &mCmd );
  1055.             }    
  1056.             
  1057.             // set the pointers to the next item. This is 8 or 9 bytes away depending on
  1058.             // whether the resulting address is odd or even
  1059.             
  1060.             cmP += 8;
  1061.             if ((unsigned long) cmP & 1 )
  1062.                 cmP++;
  1063.                 
  1064.             cmItemText = cmP;
  1065.         }
  1066.  
  1067.         HUnlock((Handle) cH );
  1068.         
  1069.         // insert the menu we just built into the system list
  1070.         
  1071.         if ( autoInstall )
  1072.             InsertMenu( mH, isHMenu? hierMenu : 0 );
  1073.     }
  1074. }
  1075.  
  1076.  
  1077. /*---------------------------------***  UNLOADMENU  ***--------------------------------*/
  1078. /*
  1079. removes this menu from the command list and un-inserts itself. It also calls itself to
  1080. deal with its submenus. Called by RemoveMenuFromBar. Use with care.
  1081. ---------------------------------------------------------------------------------------*/
  1082.  
  1083. void        ZMenuBar::UnloadMenu( MenuHandle mH )
  1084. {
  1085.     long        m;
  1086.     MenuCmd        mCmd;
  1087.     Boolean        resStatus = FALSE;
  1088.     Boolean        isResMenu = FALSE;
  1089.  
  1090.     for( m = theMenuCmds->CountItems(); m > 0; m-- )
  1091.     {
  1092.         theMenuCmds->GetArrayItem( &mCmd, m );
  1093.         
  1094.         // if this is one pertaining to the menu, delete it from the array. Also
  1095.         // if its a parent item, call this again to delete the submenu too.
  1096.     
  1097.         if ( mH == mCmd.macMenu )
  1098.         {
  1099.             theMenuCmds->DeleteItem( m );
  1100.         
  1101.             // is this a parent?
  1102.             
  1103.             if ( mCmd.theCmd == parentCmd &&
  1104.                  mCmd.subMenuID != 0 )
  1105.             {
  1106.                 // yes, so recurse and delete that too
  1107.                 
  1108.                 MenuHandle    smH = GetMenuHandle( mCmd.subMenuID );
  1109.                 
  1110.                 if ( smH )
  1111.                     UnloadMenu( smH );
  1112.             }
  1113.             
  1114.             if ( !resStatus )
  1115.             {
  1116.                 isResMenu = ( mCmd.cmdFlags & menuIsResource ) == menuIsResource;
  1117.                 resStatus = TRUE;
  1118.             }
  1119.         }
  1120.     }    
  1121.     // remove the menu from the system menu list
  1122.     
  1123.     DeleteMenu((*mH)->menuID );
  1124.     
  1125.     // dispose or release the menu handle according to whether
  1126.     // it was a resource or not
  1127.     
  1128.     if ( isResMenu )
  1129.         ReleaseResource((Handle) mH );
  1130.     else
  1131.         DisposeMenu( mH );
  1132. }    
  1133.  
  1134. /*---------------------------------***  PREDIMMENU  ***--------------------------------*/
  1135. /*
  1136. can be called recursively- dim this menu and any submenus it owns.
  1137. ---------------------------------------------------------------------------------------*/
  1138.  
  1139. void        ZMenuBar::PredimMenu( MenuHandle theMenu )
  1140. {
  1141.     short            m, i, cmd;
  1142.     MenuInfRec        mi;
  1143.     
  1144.     if ( theMenu )
  1145.     {
  1146.         // initially set all items to be dimmed except the title ( we make one
  1147.         // exception- the apple menu only has the first item dimmed );
  1148.         
  1149.         if ((*theMenu)->menuID == kAppleMenuID )
  1150.             (*theMenu)->enableFlags = 0xFFFFFFF9;
  1151.         else
  1152.         {
  1153.             // get the info rec for this menu
  1154.             
  1155.             FindMenuInfo((*theMenu)->menuID, &mi );
  1156.             
  1157.             // dim items according to dimming flags except title
  1158.             // if title already dimmed, it is not re-enabled here.
  1159.             
  1160.             if (( mi.mDimming & 0x0F ) != neverDim )
  1161.                 (*theMenu)->enableFlags &= 0x00000001;
  1162.         
  1163.             // look through the items for submenus
  1164.             
  1165.             m = CountMenuItems( theMenu );
  1166.         
  1167.             for( i = 1; i <= m; i++ )
  1168.             {
  1169.                 GetItemCmd( theMenu, i, &cmd );
  1170.                 
  1171.                 if ( cmd == hMenuCmd )
  1172.                 {
  1173.                     // Enable the parent item if permitted
  1174.                     
  1175.                     EnableItem( theMenu, i );
  1176.                 }
  1177.                 else
  1178.                 {
  1179.                     // if the item has no command and we don't want these dimming, enable it
  1180.                     
  1181.                     if ( mi.mDimming & dimCommands )
  1182.                     {
  1183.                         MenuCmd        mc;
  1184.                         
  1185.                         mc.theCmd = 0;
  1186.                         FindMCmd((((long)(*theMenu)->menuID ) << 16 ) | i, &mc );
  1187.                         
  1188.                         if ( mc.theCmd == 0 )
  1189.                             EnableItem( theMenu, i );
  1190.                     }
  1191.                     // in case the item is checked, uncheck it
  1192.                     
  1193.                     SetItemMark( theMenu, i, noMark );
  1194.                 }
  1195.             }
  1196.         }
  1197.     }    
  1198. }    
  1199.  
  1200. /*-------------------------------***  PARSEMENUITEM  ***-------------------------------*/
  1201. /*
  1202. extract command info from the item for TCL-style menu items
  1203. ---------------------------------------------------------------------------------------*/
  1204.  
  1205. void        ZMenuBar::ParseMenuItem( Str255 iText, long* aCmd )
  1206. {
  1207.     *aCmd = noCommand;
  1208.     
  1209.     // a valid command is associated with the item by appending a hash sysmbol (#),
  1210.     // followed by the command number as a string. Here we extract the number and
  1211.     // modify the string to exclude it.
  1212.     
  1213.     unsigned char    i = 1;
  1214.     Str15            subStr;
  1215.     
  1216.     // search for # char
  1217.     
  1218.     while((iText[i] != '#') && (i < iText[0]))
  1219.         i++;
  1220.     
  1221.     if ( i < iText[0] )
  1222.     {
  1223.         // extract substring which is command number in string form
  1224.         
  1225.         BlockMoveData( &iText[i + 1], &subStr[1], iText[0] - i );
  1226.         subStr[0] = iText[0] - i;
  1227.         
  1228.         StringToNum( subStr, aCmd );
  1229.         
  1230.         // truncate string
  1231.         
  1232.         iText[0] = i - 1;
  1233.     }
  1234. }    
  1235.  
  1236. /*------------------------------***  APPENDSTDITEMS  ***-------------------------------*/
  1237. /*
  1238. appends DA names or FONT names to the menu
  1239. ---------------------------------------------------------------------------------------*/
  1240.  
  1241. void        ZMenuBar::AppendStdItems( const short menuID, const short iType )
  1242. {
  1243.     MenuHandle    mH;
  1244.     
  1245.     mH = FindMenuID( menuID );
  1246.     
  1247.     if ( mH )
  1248.         AppendResMenu( mH, ( iType == appendDANames )? 'DRVR' : 'FONT' );
  1249.     
  1250.     // if we are creating a font menu, record the menuID in a global so that classes that
  1251.     // want to get info from the font menu can do so simply. ZTextWindow uses this, for example.
  1252.     
  1253.     if ( mH && ( iType == appendFontNames ))
  1254.     {
  1255.         gFontMenuID = menuID;
  1256.         SetMenuDimming( menuID, neverDim + dimTitle );
  1257.     }
  1258. }    
  1259.  
  1260.  
  1261. /*----------------------------------***  FINDMCMD  ***---------------------------------*/
  1262. /*
  1263. find the command entry associated with the mSelection value.
  1264. ---------------------------------------------------------------------------------------*/
  1265.  
  1266. void        ZMenuBar::FindMCmd( const long mSelect, MenuCmd* aCmd )
  1267. {
  1268.     long        m;
  1269.     MenuCmd        mCmd;
  1270.     
  1271.     for( m = 1; m <= theMenuCmds->CountItems(); m++ )
  1272.     {
  1273.         theMenuCmds->GetArrayItem( &mCmd, m );
  1274.     
  1275.         // is this the one we want?
  1276.         
  1277.         if ( HiWord( mSelect ) == mCmd.menuID &&
  1278.              LoWord( mSelect ) == mCmd.itemID )
  1279.         {
  1280.             *aCmd = mCmd;
  1281.             break;
  1282.         }
  1283.     }    
  1284. }    
  1285.  
  1286.  
  1287. /*--------------------------------***  FINDCOMMAND  ***--------------------------------*/
  1288. /*
  1289. inverse operation- given a command, return the original menu item and ID.
  1290. ---------------------------------------------------------------------------------------*/
  1291.  
  1292. void        ZMenuBar::FindCommand( const long cmd, short* menuID, short* itemID )    
  1293. {
  1294.     long        m;
  1295.     MenuCmd        mCmd;
  1296.     
  1297.     for( m = 1; m <= theMenuCmds->CountItems(); m++ )
  1298.     {
  1299.         theMenuCmds->GetArrayItem( &mCmd, m );
  1300.     
  1301.         // is this the one we want?
  1302.         
  1303.         if ( cmd == mCmd.theCmd )
  1304.         {
  1305.             *menuID = mCmd.menuID;
  1306.             *itemID = mCmd.itemID;
  1307.             break;
  1308.         }
  1309.     }    
  1310. }
  1311.  
  1312.  
  1313. /*------------------------------***  SETTITLEHILITE  ***-------------------------------*/
  1314. /*
  1315. set the menu title hilite on or off
  1316. ---------------------------------------------------------------------------------------*/
  1317.  
  1318. void        ZMenuBar::SetTitleHilite( const short menuID, const Boolean state )
  1319. {
  1320.     if ( state )
  1321.         HiliteMenu( menuID );
  1322.     else
  1323.         HiliteMenu( 0 );
  1324. }
  1325.  
  1326.  
  1327. /*--------------------------------***  FINDMENUID  ***---------------------------------*/
  1328. /*
  1329. returns the handle of the menu with the given ID, even if it has not been inserted into
  1330. the system list. This can only find menus that belong to this bar object however.
  1331. ---------------------------------------------------------------------------------------*/
  1332.  
  1333. MenuHandle    ZMenuBar::FindMenuID( const short menuID )
  1334. {
  1335.     // returns the handle of the menu with the given ID. This works whether or not the menu
  1336.     // was actually installed in the system menu list. If so, we use the toolbox call. If not
  1337.     // we use the slightly slower method of looking through our private array of commands to
  1338.     // locate the menu.
  1339.     
  1340.     MenuInfRec    mRec;
  1341.     
  1342.     mRec.macMenu = GetMenuHandle( menuID );
  1343.     
  1344.     if ( mRec.macMenu == NULL )
  1345.         FindMenuInfo( menuID, &mRec );
  1346.     
  1347.     return mRec.macMenu;
  1348. }
  1349.  
  1350.  
  1351. /*-------------------------------***  FINDMENUINFO  ***--------------------------------*/
  1352. /*
  1353. returns the info record for the given menu ID. This info is used to determine the right
  1354. dimming and disposal behaviour for the menu.
  1355. ---------------------------------------------------------------------------------------*/
  1356.  
  1357. void        ZMenuBar::FindMenuInfo( const short menuID, MenuInfRec* mRec )    
  1358. {
  1359.     short        n, i;
  1360.     MenuInfRec    mr;
  1361.     
  1362.     n = theMenus->CountItems();
  1363.     
  1364.     for( i = 1; i<= n; i++ )
  1365.     {
  1366.         theMenus->GetArrayItem( &mr, i );    
  1367.     
  1368.         if ( mr.menuID == menuID )
  1369.         {
  1370.             *mRec = mr;
  1371.             break;
  1372.         }
  1373.     }
  1374. }
  1375.  
  1376.  
  1377. void    ZMenuBar::GetMenuTitleRect( short menuID, Rect* tRect )
  1378. {
  1379.     // return the title rect (in GLOBAL coordinates) of the menu in the main bar with the
  1380.     // menu ID <menuID>. This returns the empty rect if no such menu was found or if the
  1381.     // menu is not in the main bar.
  1382.  
  1383.     Rect        tr = {0,0,0,0};
  1384.     MenuHandle    mH;
  1385.     mListHdl    mListH;
  1386.     short        i, iMax, tLength;
  1387.     GrafPtr        savePort, wPort;
  1388.     
  1389.     mListH = (mListHdl) LMGetMenuList();
  1390.     
  1391.     if ( mListH )
  1392.     {
  1393.         FailNILParam( mH = GetMenuHandle( menuID ));
  1394.  
  1395.         // if this handle is in the menu list, then this must be in the main bar.
  1396.         // ASSUMPTION: hierarchical menus etc. are stored elsewhere.
  1397.     
  1398.         iMax = (((*mListH)->lastMOffset ) / sizeof( mListEntry )) - 2;
  1399.         
  1400.         for ( i = 0; i < iMax; i++ )
  1401.         {
  1402.             if ( mH == (*mListH)->mListItem[i].theMenu )
  1403.             {
  1404.                 // found it! Now set up the rect
  1405.                 
  1406.                 tr.top = 1;
  1407.                 tr.bottom = GetMBarHeight();
  1408.                 
  1409.                 tr.left = (*mListH)->mListItem[i].leftEdge;
  1410.                 
  1411.                 // the right edge is tricky- we need to get the title and figure the length
  1412.                 
  1413.                 GetPort( &savePort );
  1414.                 GetWMgrPort( &wPort );
  1415.                 SetPort( wPort );
  1416.                 
  1417.                 tLength = StringWidth((*mH)->menuData ) + 10;
  1418.                 SetPort( savePort );
  1419.                 
  1420.                 tr.right = tr.left + tLength;
  1421.                 
  1422.                 break;
  1423.             }
  1424.         }    
  1425.     }
  1426.     
  1427.     *tRect = tr;
  1428. }
  1429.  
  1430.  
  1431. void        ZMenuBar::SetZoomSourceToCommand( const long aCmd )
  1432. {
  1433.     short    menuID = 0, itemID = 0;
  1434.     
  1435.     FindCommand( aCmd, &menuID, &itemID );
  1436.     
  1437.     if ( menuID )
  1438.     {
  1439.         Rect    r;
  1440.         
  1441.         GetMenuTitleRect( menuID, &r );
  1442.         InsetRect( &r, 20, 4 );
  1443.         SetGlobalZoomSource( &r );
  1444.     }
  1445. }
  1446.